compio_driver\sys\driver\iocp/
mod.rs1use std::{
2 collections::HashMap, marker::PhantomData, os::windows::io::AsRawHandle, sync::Arc,
3 time::Duration,
4};
5
6use flume::{Receiver, Sender};
7use windows_sys::Win32::{Foundation::ERROR_OPERATION_ABORTED, System::IO::OVERLAPPED};
8
9use crate::{
10 AsyncifyPool, DriverType, Entry, ErasedKey, ProactorBuilder,
11 control::Carrier,
12 sys::{driver::AwakeFlag, extra::IocpExtra, prelude::*},
13};
14
15mod cp;
16mod wait;
17
18mod_use![op];
19
20pub enum OpType {
22 Overlapped,
24 Blocking,
27 Event(RawFd),
31}
32
33pub(crate) struct Driver {
35 notify: Arc<Notify>,
36 waits: HashMap<usize, wait::Wait>,
37 pool: AsyncifyPool,
38 completed_tx: Sender<Entry>,
39 completed_rx: Receiver<Entry>,
40 _local_marker: PhantomData<ErasedKey>,
41}
42
43impl Driver {
44 pub fn new(builder: &ProactorBuilder) -> io::Result<Self> {
45 instrument!(compio_log::Level::TRACE, "new", ?builder);
46
47 let port = cp::Port::new()?;
48 let driver = port.as_raw_handle() as _;
49 let overlapped = Overlapped::new(driver);
50 let notify = Arc::new(Notify::new(port, overlapped));
51 let (completed_tx, completed_rx) = flume::unbounded();
52
53 Ok(Self {
54 notify,
55 completed_tx,
56 completed_rx,
57 waits: HashMap::default(),
58 pool: builder.create_or_get_thread_pool(),
59 _local_marker: PhantomData,
60 })
61 }
62
63 pub fn driver_type(&self) -> DriverType {
64 DriverType::IOCP
65 }
66
67 fn port(&self) -> &cp::Port {
68 &self.notify.port
69 }
70
71 pub(in crate::sys) fn default_extra(&self) -> IocpExtra {
72 IocpExtra::new(self.port().as_raw_handle() as _)
73 }
74
75 pub fn attach(&mut self, fd: RawFd) -> io::Result<()> {
76 self.port().attach(fd)
77 }
78
79 pub fn cancel(&mut self, key: ErasedKey) {
80 instrument!(compio_log::Level::TRACE, "cancel", ?key);
81 trace!("cancel RawOp");
82 let optr = key.borrow().extra_mut().optr();
83 if let Some(w) = self.waits.get_mut(&key.as_raw())
84 && w.cancel().is_ok()
85 {
86 self.port().post_raw(optr).ok();
90 }
91 trace!("call OpCode::cancel");
92 key.borrow().carrier.cancel(optr.cast()).ok();
94 }
95
96 pub fn push(&mut self, key: ErasedKey) -> Poll<io::Result<usize>> {
97 instrument!(compio_log::Level::TRACE, "push", ?key);
98 trace!("push RawOp");
99 let mut op = key.borrow();
100 let optr = op.extra_mut().optr();
101 let op_type = op.carrier.op_type();
102 match op_type {
103 OpType::Overlapped => unsafe {
104 let res = op.carrier.operate(optr.cast());
105 drop(op);
106 if res.is_pending() {
107 key.into_raw();
108 }
109 res
110 },
111 OpType::Blocking => {
112 drop(op);
113 self.push_blocking(key);
114 Poll::Pending
115 }
116 OpType::Event(e) => {
117 drop(op);
118 self.waits
119 .insert(key.as_raw(), wait::Wait::new(self.notify.clone(), e, key)?);
120 Poll::Pending
121 }
122 }
123 }
124
125 fn push_blocking(&mut self, key: ErasedKey) {
126 let notify = self.notify.clone();
127 let tx = self.completed_tx.clone();
128
129 let mut key = unsafe { key.freeze() };
132
133 let mut closure = move || {
134 let res = key.as_mut().operate_blocking();
135 let entry = Entry::new(key.into_inner(), res);
136 _ = tx.send(entry);
137 notify.wake();
138 };
139
140 while let Err(e) = self.pool.dispatch(closure) {
141 closure = e.0;
142 std::thread::yield_now();
143 }
144 }
145
146 pub fn flush(&mut self) -> bool {
147 self.notify.reset()
148 }
149
150 fn create_entry(
151 notify: *const Overlapped,
152 waits: &mut HashMap<usize, wait::Wait>,
153 entry: cp::RawEntry,
154 ) -> Option<Entry> {
155 if entry.overlapped.cast_const() == notify {
156 return None;
157 }
158
159 let entry = Entry::new(
160 unsafe { ErasedKey::from_optr(entry.overlapped) },
161 entry.result,
162 );
163
164 let Some(w) = waits.remove(&entry.user_data()) else {
166 return Some(entry);
167 };
168
169 let entry = if w.is_cancelled() {
170 Entry::new(
171 entry.into_key(),
172 Err(io::Error::from_raw_os_error(ERROR_OPERATION_ABORTED as _)),
173 )
174 } else if entry.result.is_err() {
175 entry
176 } else {
177 let key = entry.into_key();
178 let result = key.borrow().operate_blocking();
179 Entry::new(key, result)
180 };
181
182 Some(entry)
183 }
184
185 pub fn poll(&mut self, timeout: Option<Duration>) -> io::Result<()> {
186 instrument!(compio_log::Level::TRACE, "poll", ?timeout);
187
188 let notify = &self.notify.overlapped as *const Overlapped;
189
190 let mut has_entry = false;
191 while let Ok(entry) = self.completed_rx.try_recv() {
192 entry.notify();
193 has_entry = true;
194 }
195 if self.notify.reset() {
196 has_entry = true;
197 }
198
199 if !has_entry {
200 for e in self.notify.port.poll(timeout)? {
201 if let Some(e) = Self::create_entry(notify, &mut self.waits, e) {
202 self.notify.set_awake();
203 e.notify()
204 }
205 }
206 }
207 self.notify.set_awake();
208
209 Ok(())
210 }
211
212 pub fn waker(&self) -> Waker {
213 Waker::from(self.notify.clone())
214 }
215
216 pub fn pop_multishot(&mut self, _: &ErasedKey) -> Option<BufResult<usize, crate::sys::Extra>> {
217 None
218 }
219}
220
221impl AsRawFd for Driver {
222 fn as_raw_fd(&self) -> RawFd {
223 self.port().as_raw_handle() as _
224 }
225}
226
227pub(crate) struct Notify {
229 port: cp::Port,
230 overlapped: Overlapped,
231 awake: AwakeFlag,
232}
233
234impl Notify {
235 fn new(port: cp::Port, overlapped: Overlapped) -> Self {
236 Self {
237 port,
238 overlapped,
239 awake: AwakeFlag::new(),
240 }
241 }
242
243 fn set_awake(&self) {
244 self.awake.set();
245 }
246
247 fn reset(&self) -> bool {
248 self.awake.reset()
249 }
250}
251
252impl Wake for Notify {
253 fn wake(self: Arc<Self>) {
254 self.wake_by_ref();
255 }
256
257 fn wake_by_ref(self: &Arc<Self>) {
258 if !self.awake.wake() {
259 self.port.post_raw(&self.overlapped).ok();
260 }
261 }
262}